#include "state_stack.h"
#include "state.h"
#include "exceptions.h"

#include <iostream>
#include <stack>
#include <map>

using namespace krryn::core;

class state_stack::impl{
public:
	bool exists(const std::string &a_Name){
		return m_Registry.find(a_Name) != m_Registry.end();
	}

	typedef std::map<std::string, state*> map_t;
	typedef std::stack<state*> stack_t;

	stack_t m_States;
	map_t m_Registry;
	static state_stack *m_Instance;
};

void state_stack::subscribe(const std::string &a_Name, state *a_State){
	if(!m_Pimpl->exists(a_Name)){
		m_Pimpl->m_Registry[a_Name] = a_State;
	}else{
		throw duplicate_state_exception(a_Name);
	}
}

bool state_stack::empty(){
	return m_Pimpl->m_States.empty();
}

state& state_stack::current(){
	return *(m_Pimpl->m_States.top());
}

void state_stack::push(const std::string &a_Name){
	if(m_Pimpl->exists(a_Name)){
		std::clog << "Entering state: '" << a_Name << "'" << std::endl;

		if(!empty())
			current().stop();

		m_Pimpl->m_States.push(m_Pimpl->m_Registry[a_Name]);
		current().start();
	}else{
		std::clog << "Unknown state: '" << a_Name << "'" << std::endl;
	}
}

void state_stack::flush(void){
	while(!empty()){
		pop();
	}
}

void state_stack::pop(void){
	if(!empty()){
		current().stop();
		m_Pimpl->m_States.pop();

		if(!empty())
			current().start();
	}
}

state_stack *state_stack::impl::m_Instance = 0;

state_stack &state_stack::get_instance(){
	if(impl::m_Instance == 0){
		impl::m_Instance = new state_stack();
	}

	return *impl::m_Instance;
}

state_stack::state_stack(){
	m_Pimpl = new impl();
}